// Copyright (c) 2005  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of cgal-python; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with cgal-python.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Id: Py_Constrained_triangulation_plus_2.cpp 167 2007-11-02 15:36:54Z spion $
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal-python/trunk/cgal-python/bindings/Triangulations_2/Py_Constrained_triangulation_plus_2.cpp $
//
// Author(s)     : Naceur Meskini
//=========================================================================


// include ====================================================================
#include <CGAL/basic.h>
#include <include/Kernels.h>
#include <include/iterator.h>
#include <CGAL/Constrained_triangulation_plus_2.h>
#include "Py_Constrained_triangulation_plus_2_doc.h"

#include <CGAL/Alpha_shape_vertex_base_2.h>
#include <CGAL/Triangulation_hierarchy_vertex_base_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>

#include <CGAL/Alpha_shape_face_base_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>

// Boost include ==============================================================
#include <boost/python.hpp>
#include <boost/cstdint.hpp>
#include <list>
// Using =======================================================================
using namespace boost::python;

// Declarations ================================================================
namespace  {

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(insert_overloads_1_2, insert, 1, 2)

}// namespace 

template < class kernel,class Triangulation>
void py_insert(Triangulation& dt,boost::python::list pts)
{
	typedef typename kernel::Point_2 Point_2;
	for(int i = 0 ; i < pts.attr("__len__")() ; i++)
	{
		Point_2 P = boost::python::extract<Point_2>(pts[i]); 
		dt.insert(P);
	}
}
template < class iterator,class Ctp,class Vertex_handle>
simple_python_iterator<iterator> py_vertices_in_constraint( Ctp& ctp,Vertex_handle va,Vertex_handle vb)
{
	std::pair< iterator , iterator > p( ctp.vertices_in_constraint_begin(va,vb), ctp.vertices_in_constraint_end(va,vb) );
	return simple_python_iterator<iterator>(p);
}
template < class iterator,class Ctp>
simple_python_iterator<iterator> py_constraints(Ctp& ctp)
{
	std::pair< iterator , iterator > p( ctp.constraints_begin(), ctp.constraints_end() );
	return simple_python_iterator<iterator>(p);
}
template < class iterator,class Ctp>
simple_python_iterator<iterator> py_subconstraints(Ctp& ctp)
{
	std::pair< iterator , iterator > p( ctp.subconstraints_begin(), ctp.subconstraints_end() );
	return simple_python_iterator<iterator>(p);
}

template < class iterator,class Ctp>
simple_python_iterator<iterator> py_contexts(Ctp& ctp,typename Ctp::Vertex_handle v1,typename Ctp::Vertex_handle v2)
{
	std::pair< iterator , iterator > p( ctp.contexts_begin(v1,v2), ctp.contexts_end(v1,v2) );
	return simple_python_iterator<iterator>(p);
}

// exporting method ======================================================================
template <class kernel>
void Py_Constrained_triangulation_plus_2()
{
	// three things must be fixed in order to insure the derivation in the python side.
	// -1: the vertex_base 
	// -2: the face_base
	// -3: the data_structure
	typedef CGAL::Alpha_shape_vertex_base_2<kernel> 	Avb;
	typedef CGAL::Triangulation_hierarchy_vertex_base_2<Avb> Hv; //this one is needed when the input data set is huge for the Alpha_shape_2,
																 // say more than 10.000 points,
	typedef CGAL::Triangulation_vertex_base_with_info_2<boost::python::object,kernel,Hv> 	Vb;

	typedef CGAL::Delaunay_mesh_face_base_2<kernel> 	Mf; 
	typedef CGAL::Alpha_shape_face_base_2<kernel,Mf> 	Af;

	typedef CGAL::Triangulation_data_structure_2<Vb,Af> Tds;

	typedef CGAL::Triangulation_2<kernel,Tds>   										Triangulation_2;
	typedef typename Triangulation_2::Edge 												Edge;

	typedef CGAL::Exact_predicates_tag 													Exact_predicates_tag;
	typedef CGAL::Constrained_triangulation_2<kernel,Tds,Exact_predicates_tag>   		Constrained_triangulation_2;
	typedef typename Constrained_triangulation_2::Constraint							Constraint;

	typedef typename Constrained_triangulation_2::Face_handle 							Face_handle;
	typedef typename Constrained_triangulation_2::Vertex_handle 						Vertex_handle;

	typedef typename Triangulation_2::Locate_type 										Locate_type;
	typedef typename kernel::Point_2 													Point_2;
	typedef typename std::list<Edge>::iterator  EdgeIterator;

	typedef CGAL::Constrained_triangulation_plus_2<Constrained_triangulation_2>   		Constrained_triangulation_plus_2;
	typedef typename Constrained_triangulation_plus_2::Vertices_in_constraint_iterator	Vertices_in_constraint_iterator;
	typedef typename Constrained_triangulation_plus_2::Constraint_iterator				Constraint_iterator;
	typedef typename Constrained_triangulation_plus_2::Subconstraint_iterator			Subconstraint_iterator;
	typedef typename Constrained_triangulation_plus_2::Context_iterator					Context_iterator;

    class_< Constrained_triangulation_plus_2, bases<Constrained_triangulation_2> >("Constrained_triangulation_plus_2",doc_Constrained_triangulation_plus_2, init< optional< const kernel& > >())
        .def(init< const Constrained_triangulation_plus_2& >(doc_init))
		.def(init< std::list<Constraint,std::allocator<Constraint > >&, optional< const kernel& > >())

		.def("insert_constraint", (void (Constrained_triangulation_plus_2::*)(const Point_2&, const Point_2&) )&Constrained_triangulation_plus_2::insert_constraint,doc_insert_constraint)
		.def("insert_constraint", (void (Constrained_triangulation_plus_2::*)(Vertex_handle, Vertex_handle) )&Constrained_triangulation_plus_2::insert_constraint)
        .def("push_back", (Vertex_handle (Constrained_triangulation_plus_2::*)(const Point_2&) )&Constrained_triangulation_plus_2::push_back,doc_push_back)
        .def("push_back", (void (Constrained_triangulation_plus_2::*)(const Constraint&) )&Constrained_triangulation_plus_2::push_back)

		.def("insert", (Vertex_handle (Constrained_triangulation_plus_2::*)(const Point_2&, Face_handle) )&Constrained_triangulation_plus_2::insert, insert_overloads_1_2(doc_insert))
		.def("insert", (Vertex_handle (Constrained_triangulation_plus_2::*)(const Point_2&, Locate_type, Face_handle, int) )&Constrained_triangulation_plus_2::insert)
		.def("insert",&py_insert<kernel,Constrained_triangulation_plus_2>)

        .def("remove_constraint", (void (Constrained_triangulation_plus_2::*)(Vertex_handle, Vertex_handle) )&Constrained_triangulation_plus_2::remove_constraint,doc_remove_constraint)
        .def("context", &Constrained_triangulation_plus_2::context,doc_context)
		.def("contexts",&py_contexts<Context_iterator,Constrained_triangulation_plus_2>,doc_contexts)
        .def("number_of_enclosing_constraints", &Constrained_triangulation_plus_2::number_of_enclosing_constraints,doc_number_of_enclosing_constraints)
        .def("number_of_constraints", &Constrained_triangulation_plus_2::number_of_constraints,doc_number_of_constraints)
        .def("number_of_subconstraints", &Constrained_triangulation_plus_2::number_of_subconstraints,doc_number_of_subconstraints)
		.def("vertices_in_constraint",&py_vertices_in_constraint<Vertices_in_constraint_iterator,Constrained_triangulation_plus_2,Vertex_handle>)
		.add_property("constraints",&py_constraints<Constraint_iterator,Constrained_triangulation_plus_2>)
		.add_property("subconstraints",&py_subconstraints<Subconstraint_iterator,Constrained_triangulation_plus_2>)

    ;

	simple_python_iterator<Vertices_in_constraint_iterator>::declare("Vertices_in_constraint_iterator");
	simple_python_iterator<Constraint_iterator>::declare("Constraint_iterator","\n\niterator over Constraints");
	simple_python_iterator<Subconstraint_iterator>::declare("Subconstraint_iterator","\n\niterator over Subconstraints");
	simple_python_iterator<Context_iterator>::declare("Context_iterator","\n\niterator over Contexts");
}

void export_Constrained_triangulation_plus_2()
{
	Py_Constrained_triangulation_plus_2<K>();
}
